首先一定要來說說Babylon.js 提供的 BABYLON.WebXRDefaultExperience
這個強大的物件,處理好所有底層的 XR 設置,就是希望我們只要便利的使用一行程式碼就可以快速初始化一個功能完善的 WebXR 場景。適合一個要快速驗證或沒有太多客製化的時候使用。
// 啟動 WebXR 體驗
const xr = await scene.createDefaultXRExperienceAsync({
optionalFeatures: true // 選項參數 (可選)
});
這一行做了什麼?
XR 攝影機管理:自動創建並設定 XR 專用的雙眼攝影機。
XR 模式 UI:自動在畫面上生成一個按鈕,讓使用者可以輕鬆進入或退出 VR 模式。
控制器與輸入源:自動偵測並設定連接的 XR 控制器,並提供預設的傳送(Teleportation)或移動功能。
XR 特性支援:整合了常用的功能,如空間追蹤(Spatial Tracking)、傳送指示器(Teleportation Pointers)等。
偵測使用者是否佩戴了 XR 裝置。
管理 XR 模式的進入與退出。
創建一個特殊的 XR 攝影機,這個攝影機會與使用者的頭部追蹤數據同步。
處理雙眼立體渲染。
提供預設的傳送或移動功能。
當我們需要自己去客製化各種設定而不是只使用default的時候,我們需要使用BABYLON.WebXRExperienceHelper
。BABYLON.WebXRDefaultExperience
的底層就是用BABYLON.WebXRExperienceHelper
定給予初始值讓大家可以快速初始化一個XR起來。當我們要使用WebXRExperienceHelper來個別設定的時候要做的事情如下:
首先,你需要初始化 Helper 並設定底層的 XR Session Manager。
// 1. 創建 XR Helper 實例
const xrHelper = await BABYLON.WebXRExperienceHelper.CreateAsync(scene);
// 2. 存取 Session Manager
const sessionManager = xrHelper.sessionManager;
1. 進入或退出 XR 模式的 UI
需要手動創建一個 HTML 按鈕,並在點擊時呼叫 sessionManager 的方法來啟動或結束 XR Session。要注意的是一旦進入到XR的環境,所有遠本HTML設定的按鈕都會看不見唷!因為我們已經進入canvas的裡面了。在XR的世界裡的UI就應該要用3D世界的方式製作,當我們用babylon.js時就會使用Babylon.GUI
,在 3D 空間中創建一個虛擬按鈕,例如一個懸浮在手上的面板等方式來呈現。退出XR必須使用Babylon.GUI建立按鈕後手動呼叫 sessionManager.exitXRAsync() 來結束,然後同時生命週期onXRSessionEnd 事件也會被觸發。在上一篇分享的傳送門範例,就是因為沒有做退出XR模式,所以會有當使用頭戴顯示器時會不能退出只能強制關機的情形唷。
// 進入XR
const startXRButton = document.createElement("button");
startXRButton.textContent = "進入 VR";
startXRButton.id = "xr-start-button";
document.body.appendChild(startXRButton);
// 監聽按鈕點擊事件
startXRButton.onclick = async () => {
// 檢查瀏覽器是否支援 'immersive-vr' 模式
const isSupported = await sessionManager.isSessionSupportedAsync('immersive-vr');
if (isSupported) {
// 請求進入 XR 模式
await sessionManager.enterXRAsync(
'immersive-vr', // 模式類型
'local-floor', // 參考空間類型 (允許在房間內平移)
);
} else {
console.error("此裝置不支援沉浸式 VR 模式。");
}
};
2. XR攝影機設定
因為XR的開發時,攝影機也會使用專用的攝影機設定,而在WebXRExperienceHelper實例本身就有一個camera可以使用,並且我們可以設定太近的會被裁剪,以確保不會看到攝影機內部或使用者頭部模型等不該顯示的東西:
// 在進入 XR 模式後,你可以這樣存取攝影機
const xrCamera = xrHelper.camera;
// 剪掉太近的設定
xrCamera.minZ = 0.1;
3. 實做控制器的互動
如果沒有WebXRDefaultExperience自動載入,就需要手動來控制包含頭戴顯示的3D模型載入和監聽控制器的事件、傳送功能以及傳送的雷射線的設定等:
// 監聽新控制器連接的事件
xrHelper.input.onControllerAddedObservable.add((controller) => {
console.log("偵測到新的 XR 控制器:", controller.handness);
// 1. 手動加載控制器 3D 模型 (取代 DefaultExperience 的自動載入)
// 這是非同步操作,確保模型加載完畢
controller.onMotionControllerInitObservable.add((motionController) => {
// 載入與此控制器類型相符的 3D 模型
controller.loadModel();
});
// 2. 監聽按鈕/扳機事件 (取代自動行為)
// 假設我們監聽右控制器的扳機 (Trigger)
if (controller.handness === 'right') {
controller.onTriggerStateChangedObservable.add((state) => {
if (state.value > 0.9) {
console.log("右控制器扳機被按下!");
// 在這裡實作你的發射/抓取邏輯
}
});
}
// 3. 建立傳送功能實例
const teleportation = new BABYLON.WebXRControllerTeleportation({
floorMeshes: [ground], // 設置可傳送的地面網格
xrInput: xrHelper.input
}, xrHelper.baseExperience);
teleportation.setTargetMesh({ diameter: 0.5, segments: 16 });
// 4. 調整傳送指示器 (Teleportation Pointers) 樣式
// 傳送雷射線也是這個物件的一部分
teleportation.laserPointer.alpha = 0.8;
teleportation.laserPointer.color = BABYLON.Color3.Blue();
});